function GameObject2(id) {
    this.x = 0;
    this.y = 0;
    this.id = id;

}

GameObject2.method('setID', function (value) {
    this.id = value;
    return this;
});

GameObject2.method('getID', function () {
    return this.id;
});

GameObject2.method('setPos', function (x_abs, y_abs) {
    this.x = x_abs * OurGame.grid;
    this.y = y_abs * OurGame.grid;
//    checkForAndAddUpgrade(level.map[x_abs][y_abs], OurGame.players.indexOf(this));
});

GameObject2.method('getPosX', function () {
    return Math.ceil(this.x / OurGame.grid);
});

GameObject2.method('getPosY', function () {
    return Math.ceil(this.y / OurGame.grid);
});

GameObject2.method('draw', function () {
    stickyError("DRAW should be overridden!", "DRAW should be overridden!");
});

function Player(id) {
    this.setID(id);
    this.x_move = 0;
    this.y_move = 0;
    this.movementDirection = 'right'; // possible values are left, up, right, down
    this.type = PlayerType.HUMAN;
    this.speed = 6;
    this.lives = 3;
    this.kills = 0;
    this.currentlyAvailableBombs = 1;
    this.currentlyPlantedBombs = 0;
    this.bombRadius = 2;
    this.assingedKeys = null;

    this.immortalTimerTime = 120;
    this.immortalTimer = null;
    this.immortalTimer = this.immortalTimerTime;

    this.animationTimer = 0;
    this.speedAnimationConst = 1;

    // limitations
    this.totalBombsLimit = 6;
    this.maxSpeedLimit = 10;
    this.maxExplosionRadiusLimit = 19;

    //packet sync.
    this.nrOfMoves = 0;
    this.lastRecievedNr = 0;
}

Player.inherits(GameObject2);

Player.method('moveX', function (n) {
    this.x_move += n * OurGame.grid;
    this.nrOfMoves++;
    makeMove(this, n, 0);
});

Player.method('moveY', function (n) {
    this.y_move += n * OurGame.grid;
    this.nrOfMoves++;
    makeMove(this, 0, n);
});

Player.method('isMoving', function () {
    return (this.x_move != 0 || this.y_move != 0);
});

Player.method('isAlive', function () {
    return this.lives > 0;
});

Player.method('bombExploded', function () {
    this.currentlyPlantedBombs--;
    updatePlayerSidebarBombs(this);
});

Player.method('addUpgrade', function (upgradeNo) {
    switch (upgradeNo) {
        case '1':
            if (this.currentlyAvailableBombs < this.totalBombsLimit) {
                this.currentlyAvailableBombs++;
                updatePlayerSidebarBombs(this);
                return true;
            }
            break;
        case '2':
            if (this.speed < this.maxSpeedLimit) {
                this.speed++;
                return true;
            }
            break;
        case '3':
            if (this.bombRadius < this.maxExplosionRadiusLimit) {
                this.bombRadius++;
                return true;
            }
            break;
    }
    return false;
});

Player.method('getActiveBombsCount', function () {
    return this.currentlyPlantedBombs;
});

Player.method('removeLife', function () {
    var lifeWasRemoved = false;
    if (this.lives != 0 && this.immortalTimer > this.immortalTimerTime) {
        this.lives--;
        updatePlayerSidebar(this);
        lifeWasRemoved = true;
        this.immortalTimer = 0;
    }
    // when I die bomb sounds stay on, they have to be silenced
    if (this.lives == 0) {
        for (var i = 0; i < OurGame.bombs.length; i ++) {
            if (OurGame.bombs[i]) {
                if (OurGame.bombs[i].expansionSoundInstance instanceof Audio) {
                    OurGame.bombs[i].expansionSoundInstance.pause();
                }
            }
        }
    }
    return lifeWasRemoved;
});

Player.method('addKills', function () {
    this.kills++;
    updatePlayerSidebar(this);
});

Player.method('isCurrentPlaceFreeOfBombs', function () {
    var result = getItemIndexByPos(OurGame.bombs, this.getPosX(), this.getPosY());
    return result == -1;
});

Player.method('plantBomb', function (bombx, bomby) {
    var iX = bombx || this.x;
    var iY = bomby || this.y;
    iX = Math.floor(iX / OurGame.grid);
    iY = Math.floor(iY / OurGame.grid);
    var index = OurGame.bombs.indexOf(undefined);
    if (index == -1) {
        OurGame.bombs.push(new Bomb(bombUniqueID(), iX, iY, this, this.bombRadius));
    } else {
        OurGame.bombs[index] = new Bomb(bombUniqueID(), iX, iY, this, this.bombRadius);
    }
    this.currentlyPlantedBombs++;
    updatePlayerSidebarBombs(this);
//    log('PlantBomb() is called');
});

Player.method('assignKeys', function (keys) {
    this.assingedKeys = keys;
});

Player.method('draw', function () {
    var imagesOnSprite = 6;
    var movementSprite;
    try {
        OurGame.ctx.save();
        if (this.immortalTimer < this.immortalTimerTime && Math.round(this.immortalTimer / 10) % 2 == 0) {
            OurGame.ctx.globalAlpha = 0.5;
        }
        movementSprite = Math.round(this.animationTimer / this.speed * this.speedAnimationConst * (imagesOnSprite - 1));
        if (this.movementDirection == 'left') {
            this.drawMovement(0, 1 * movementSprite);
        }
        else if (this.movementDirection == 'right') {
            this.drawMovement(1, 1 * movementSprite);
        }
        else if (this.movementDirection == 'up') {
            this.drawMovement(2, 1 * movementSprite);
        }
        else if (this.movementDirection == 'down') {
            this.drawMovement(3, 1 * movementSprite);
        }

        OurGame.ctx.restore()
    } catch (e) {
        stickyError('Player draw error occurred!', 'player.draw error ' + e);
    }
});

Player.method('drawMovement', function (row, column) {
    if (OurGame.isMultiplayer == true) {
        myIndex = OurGame.players.indexOf(this);
    } else {
        myIndex = this.getID();
    }
    OurGame.ctx.drawImage(OurGame.images["characters/c" + (myIndex + 1)], column * OurGame.maxGrid, row * OurGame.maxGrid, OurGame.maxGrid, OurGame.maxGrid, this.x - OurGame.offSet, this.y - OurGame.offSet, OurGame.maxGrid, OurGame.maxGrid);
});

Player.method('update', function () {
    if (this.animationTimer == this.speed) {
        this.animationTimer = 0;
    }
    else if (this.isMoving()) {
        this.animationTimer++;
    }
    this.immortalTimer++;
    var isChanged = false;

    var old_x = this.x;
    var old_y = this.y;

    if (this.x_move > 0 && this.x - this.x_move <= OurGame.grid * 18) {
        this.movementDirection = 'right';
        this.x_move -= this.speed;
        this.x += this.speed;
        if (this.x_move < 0) {
            this.x += this.x_move;
            this.x_move = 0;
        }
        isChanged = true;
        removeMatrixObject(old_x, old_y, this.id, "p");
        return isChanged;
    }
    if (this.x_move < 0 && this.x + this.x_move >= 0) {
        this.movementDirection = 'left';
        this.x_move += this.speed;
        this.x -= this.speed;
        if (this.x_move > 0) {
            this.x += this.x_move;
            this.x_move = 0;
        }
        isChanged = true;
        removeMatrixObject(old_x, old_y, this.id, "p");
        return isChanged;
    }
    if (this.y_move > 0 && this.y - this.y_move <= OurGame.grid * 15) {
        this.y_move -= this.speed;
        this.y += this.speed;
        this.movementDirection = 'down';
        if (this.y_move < 0) {
            this.y += this.y_move;
            this.y_move = 0;
        }
        isChanged = true;
        removeMatrixObject(old_x, old_y, this.id, "p");
        return isChanged;
    }
    if (this.y_move < 0 && this.y + this.y_move >= 0) {
        this.y_move += this.speed;
        this.y -= this.speed;
        this.movementDirection = 'up';
        if (this.y_move > 0) {
            this.y += this.y_move;
            this.y_move = 0;
        }
        isChanged = true;
        removeMatrixObject(old_x, old_y, this.id, "p");
        return isChanged;
    }
});